(ns com.ufo5260987423.graphDatabase.core.clojure.core.client
  (:use com.ufo5260987423.graphDatabase.core.clojure.core.utils)
  (:use com.ufo5260987423.graphDatabase.core.clojure.core.route)
  (:import (java.net Socket)
           (java.io PrintWriter InputStreamReader BufferedReader)
           (com.ufo5260987423.graphDatabase.core.connector REPL_Connector)))

(println "load core.client")

(def history-map (ref {}))
(def repl_connector_instance REPL_Connector/repl_connector_instance)
(def connector-pool nil)
(declare conn-handler)
(declare connect)

(defn create-connect [ip port]
  (connect (server ip (Integer. port))))

(defn get-connector-pool [servers]
  (reduce #(conj %1 {%2 (apply create-connect %2)}) {} servers))

(def local (parse_address (.getLocal repl_connector_instance)))
(def servers (vec (map parse_address (seq (.getServers repl_connector_instance)))))

(defn init []
  (def connector-pool (get-connector-pool servers))
  (def servers (create-servers servers))
  (def local (get connector-pool local))
  true)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn connect [server]
  (let [socket (Socket. (:name server) (:port server))
        in (BufferedReader. (InputStreamReader. (.getInputStream socket)))
        out (PrintWriter. (.getOutputStream socket))
        conn (ref {:in in :out out})]
    (doto (Thread. #(conn-handler conn)) (.start))
    conn))

(defn write [conn msg]
  (dosync
    (let [id (count @history-map)
          sendMsg {id msg}]
      (ref-set history-map (conj @history-map {id (promise)}))
      (doto (:out @conn)
        (.println (str sendMsg "\r"))
        (.flush))
      id)))


(defn handle-history-promise [target]
  (loop [flag (promise? (get @history-map (first (first target))))]
    (if flag
      (if (not (empty? target))
        (dosync (deliver (get @history-map (first (first target))) (last (first target)))))
      (recur (promise? (get @history-map (first (first target))))))))

(defn conn-handler [conn]
  (while (nil? (:exit @conn))
    (let [msg (.readLine (:in @conn))]
      (if (not (nil? msg))
        (handle-history-promise (eval-string msg))
        msg))))

(defn get-conn [conn-key]
  (if (nil? (get connector-pool conn-key))
    (conj connector-pool {conn-key (apply create-connect conn-key)}))
  (get connector-pool conn-key))

(defn write-with-reply [conn msg]
  (if (nil? msg)
    nil
    (if (= conn local)
      (eval msg)
      (loop [x (write conn msg)]
        (if (realized? (@history-map x))
          @(@history-map x)
          (recur x))))))
